package com.ququ.syb.mqhandler.service;

import com.alibaba.fastjson.JSON;
import com.ququ.common.utils.AESUtil;
import com.ququ.common.utils.MD5Util;
import com.ququ.common.utils.OkHttpClientUtil;
import com.ququ.syb.common.constant.PayOrderStatusConstant;
import com.ququ.syb.common.constant.PayOrderTypeConstant;
import com.ququ.syb.common.constant.RabbitMqQueueNameConstant;
import com.ququ.syb.common.constant.RedisKeyConstant;
import com.ququ.syb.common.pojo.PayCallbackLog;
import com.ququ.syb.common.pojo.PayOrder;
import com.ququ.syb.mqhandler.fegin.ApplicationFegin;
import com.ququ.syb.mqhandler.fegin.PayOrderFegin;
import com.ququ.syb.mqhandler.mongodb.PayCallbackLogDao;
import com.ququ.syb.mqhandler.rabbitmq.RabbitMQSender;
import com.ququ.syb.mqhandler.redis.RedisDao;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class PayOrderNotifyService {
    @Autowired
    private PayOrderFegin payOrderFegin;
    @Autowired
    private ApplicationFegin applicationFegin;
    @Autowired
    private RedisDao redisDao;
    @Autowired
    private PayCallbackLogDao payCallbackLogDao;
    @Autowired
    private RabbitMQSender rabbitMQSender;

    private Logger logger = LoggerFactory.getLogger(PayOrderNotifyService.class);

    private final long MAX_COUNT = 10L;

    public void payOrderNotify(String tradenum){
        Jedis jedis = redisDao.getJedis();
        try {
            PayOrder payOrder = payOrderFegin.getPayOrder(tradenum).getData();
            if (payOrder == null) {
                logger.debug("{}支付订单不存在，无法向应用发送回调", tradenum);
                return;
            }
            String countKey = payOrder.getType()==PayOrderTypeConstant.ASSURE && payOrder.getStatus() == PayOrderStatusConstant.PAY_TO_ASSURE_SUCCESS? RedisKeyConstant.PAY_CALLBACK_COUNT + "assure:" +tradenum : RedisKeyConstant.PAY_CALLBACK_COUNT + tradenum;
            if (jedis.incr(countKey) > MAX_COUNT) {
                logger.debug("{}订单异步回调通知次数已经超限", tradenum);
                return;
            }
            if (!(payOrder.getStatus() == PayOrderStatusConstant.SUCCESS || payOrder.getStatus() == PayOrderStatusConstant.FAIL || payOrder.getStatus() == PayOrderStatusConstant.PAY_TO_ASSURE_SUCCESS)) {
                logger.debug("{}支付订单不是成功或失败状态，不发起应用回调", tradenum);
                return;
            }
            if (StringUtils.isBlank(payOrder.getCallbackurl()) || !payOrder.getCallbackurl().startsWith("http")) {
                logger.debug("{}支付订单回调地址错误，不发起应用回调", tradenum);
                return;
            }

            Map<Integer, String> statusmsg = new HashMap<>();
            statusmsg.put(PayOrderStatusConstant.SUCCESS, "担保订单收款成功");
            statusmsg.put(PayOrderStatusConstant.FAIL, "担保订单预收款失败");
            statusmsg.put(PayOrderStatusConstant.ASSURE_REFUND_SUCCESS, "担保订单退款成功");
            statusmsg.put(PayOrderStatusConstant.ASSURE_CONFIRM_FAIL, "担保订单确认失败");
            statusmsg.put(PayOrderStatusConstant.ASSURE_REFUND_FAIL, "担保订单退款失败");
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("tradenum", tradenum);
            map.put("outorderno", payOrder.getOutorderno());
            map.put("amount", payOrder.getAmount());
            map.put("paycommission", payOrder.getPaycommission());
            map.put("payeecommission", payOrder.getPayeecommission());
            map.put("costcommission", payOrder.getCostcommission() == null ? 0 : payOrder.getCostcommission());
            map.put("status", payOrder.getStatus());
            map.put("privatedata", payOrder.getPrivatedata());
            map.put("assuremsg", payOrder.getType() == PayOrderTypeConstant.ASSURE ? statusmsg.get(payOrder.getStatus()) : "不是担保订单");
            map.put("assure", payOrder.getType() == PayOrderTypeConstant.ASSURE ? 1 : 0);
            logger.debug("支付回调参数:{}", map.toString());
            String appkey = applicationFegin.getApplicationKey(payOrder.getAppcode()).getData();
            if (!StringUtils.isBlank(appkey) && appkey.length() == 32) {
                appkey = appkey.substring(8, 24);
            }
            String data = JSON.toJSONString(map);
            String sign = MD5Util.md5(MD5Util.md5(data + appkey).toLowerCase()).toLowerCase();
            Map<String, String> notifyMap = new HashMap<>();
            notifyMap.put("data", data);
            notifyMap.put("sign", sign);
            //记录回调日志到MongoDB
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            PayCallbackLog payCallbackLog = new PayCallbackLog();
            payCallbackLog.setTime(sdf.format(new Date()));
            payCallbackLog.setCallbackUrl(payOrder.getCallbackurl());
            payCallbackLog.setTradenum(tradenum);
            payCallbackLog.setParams(map);
            payCallbackLog = payCallbackLogDao.save(payCallbackLog);
            String encryptData = AESUtil.encrypt(JSON.toJSONString(notifyMap), appkey);
            String result = null;
            logger.debug("向应用发起支付订单异步通知:{}", tradenum);
            Map<String, Object> notify_Map = new HashMap();
            notify_Map.put("data", encryptData);
            notify_Map.put("appcode", payOrder.getAppcode());
            result = OkHttpClientUtil.post(payOrder.getCallbackurl(), notify_Map, null);
            logger.debug("支付订单异步通知应用返回结果:{}", result);
            payCallbackLog.setResponse(result);
            payCallbackLogDao.save(payCallbackLog);
            logger.info("noify result:" + result);
            rabbitMQSender.send(RabbitMqQueueNameConstant.NOTIFY_PAYORDER_DEAD, tradenum, 10 * 60 * 1000l);    //无论成功与否，隔10分钟重发，发10次结束
        }catch (Exception e){
            logger.error("支付订单异步通知给应用时异常",e);
            rabbitMQSender.send(RabbitMqQueueNameConstant.NOTIFY_PAYORDER_DEAD, tradenum, 10 * 60 * 1000l);    //无论成功与否，隔10分钟重发，发10次结束
        }finally {
            redisDao.close(jedis);
        }
    }
}
